// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// go:构建达尔文| | |蜻蜓| | freebsd | | linux | | netbsd | openbsd
// +构建达尔文蜻蜓freebsd linux netbsd openbsd

package bio

import (
	"runtime"
	"sync/atomic"
	"syscall"
)

// mmapLimit是之前要创建的最大mmaped区域数
// 返回到读取到堆分配的片。这是存在的
// 因为有些操作系统对
// 每个进程都有不同的映射区域。在撰写本文时：
// None
// 达尔文无限
// 蜻蜓1000000（虚拟机最大进程）
// FreeBSD无限
// Linux 65530（vm.max\u map\u计数）
// 无限制上网本
// OpenBSD无限
var mmapLimit int32 = 1<<31 - 1

func init() {
	// Linux是唯一一个实际关注的操作系统。
	if runtime.GOOS == "linux" {
		mmapLimit = 30000
	}
}

func (r *Reader) sliceOS(length uint64) ([]byte, bool) {
	// 对于小的切片，不要为一个
	// 映射，尤其是因为我们无法取消映射。
	const threshold = 16 << 10
	if length < threshold {
		return nil, false
	}

	// 我们达到mmap限制了吗？
	if atomic.AddInt32(&mmapLimit, -1) < 0 {
		atomic.AddInt32(&mmapLimit, 1)
		return nil, false
	}

	// 页面对齐偏移量。
	off := r.Offset()
	align := syscall.Getpagesize()
	aoff := off &^ int64(align-1)

	data, err := syscall.Mmap(int(r.f.Fd()), aoff, int(length+uint64(off-aoff)), syscall.PROT_READ, syscall.MAP_SHARED|syscall.MAP_FILE)
	if err != nil {
		return nil, false
	}

	data = data[off-aoff:]
	r.MustSeek(int64(length), 1)
	return data, true
}
